<template>
  <div>
    <el-row type="flex" justify="center" align="middle">
      <el-select v-model="formData.value" placeholder="请选择设备">
        <el-option
          v-for="(item, index) in devices"
          :key="index"
          :label="item.device"
          :value="item.device"
        >
          <span>{{ item.device }}</span>
        </el-option>
      </el-select>
      <el-col :span="3">
        <el-button @click="startPFPDRLocation('pf')" type="primary">
          开始定位
        </el-button>
      </el-col>
      <el-col :span="3">
        <el-button @click="stopLocation()" type="primary">停止定位</el-button>
      </el-col>
      <el-col :span="3">
        <el-button @click="startWifiLocation('wifi')" type="primary">
          显示指纹定位
        </el-button>
      </el-col>
    </el-row>
    <p></p>
    <div id="map" class="map" tabindex="0"></div>
    <span id="mousePosition" style="display: inline-block; float: right" />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <!-- 写死的事件 -->
    <el-row>
      <!-- <el-button @click="startLocation('9link')" type="primary">
        开始定位(9link)(轮询)
      </el-button> -->
      <el-button @click="startWifiLocation('wifi')" type="primary">
        Wifi指纹定位
      </el-button>
      <el-button @click="startPFPDRLocation('pf')" type="primary">
        开始定位(pf+pdr)
      </el-button>
      <el-button @click="stopLocation()" type="primary">停止定位</el-button>
      <el-button @click="clearView()" type="primary">清空标记</el-button>
      <el-button @click="moveDemo()" type="primary">moveDemo</el-button>
      <!-- <br />
      <br />
      <el-button @click="addFeature('qwe', 30000, -81500, 'location')" type="primary">
        新增
      </el-button>
      <el-button @click="removeFeature('qwe')" type="primary">移除</el-button>
      <el-button @click="movePointTo('qwe', 10000, -81500)" type="primary">
        移动
      </el-button>
      <el-button @click="movePointTo('qwe', 10000, -61500)" type="primary">
        移动-2
      </el-button>
      <br />
      <br />
      <el-button @click="addFeature('asd', 30000, -61500, 'location')" type="primary">
        新增2
      </el-button>
      <el-button @click="removeFeature('asd')" type="primary">移除2</el-button>
      <br />
      <br /> -->
      <el-button @click="output()" type="primary">导出</el-button>
    </el-row>
    <ul>
      <li v-for="(item, index) in pointFeatures" :key="index">
        {{ item.id_ }}
        <!--- {{ item.values_.geometry.flatCoordinates }}-->
      </li>
    </ul>
  </div>
</template>

<script>
// import f5polygon from '../assets/f5polygon'
// import f5door from '../assets/f5door'

import { mapActions, mapState } from 'vuex'
import axios from 'axios'
import 'ol/ol.css'
import GeoJSON from 'ol/format/GeoJSON'
import { Map as olMap, View as olView, Feature as olFeature } from 'ol'
import { Point, LineString } from 'ol/geom'
import { Fill, Stroke, Style, Circle as CircleStyle, Icon } from 'ol/style'
import { Vector as VectorSource, OSM } from 'ol/source'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
import { MousePosition, ScaleLine } from 'ol/control'
import { toStringXY, createStringXY } from 'ol/coordinate'

export default {
  data() {
    return {
      baseFeature: [],
      map: null, // 地图图层
      styles: {}, // POI 样式
      mousePositionControl: null, // 鼠标坐标控制器
      scenes: new Map(), // 定位场景（Hash）
      pointSources: {}, // 点数据源
      pathSources: {}, // 线数据源
      timer: null, // 定时器
      pointFeatures: {},
      webSockets: new Map(),
      formData: {
        value: '',
      },
    }
  },

  methods: {
    ...mapActions(['getDevices']),
    initWebSource() {
      axios
        .get(
          '/geoserver/zjut/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=zjut%3Acs_f5_polygon&maxFeatures=100&outputFormat=application%2Fjson'
        )
        .then(
          (response) => {
            // console.log(response.data)
            this.baseFeature.push(response.data) // Type is MultiPolygon
          },
          (error) => {
            console.log('fail', error)
          }
        )
      axios
        .get(
          '/geoserver/zjut/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=zjut%3Acs_f5_door&maxFeatures=100&outputFormat=application%2Fjson'
        )
        .then(
          (response) => {
            // console.log(response.data)
            this.baseFeature.push(response.data) // Type is MultiLineString
          },
          (error) => {
            console.log('fail', error)
          }
        )
      axios
        .get(
          '/geoserver/zjut/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=zjut%3Acs_f5_wifi_reference_point&maxFeatures=50&outputFormat=application%2Fjson'
        )
        .then(
          (response) => {
            // console.log(response.data)
            this.baseFeature.push(response.data) // Type is Point
          },
          (error) => {
            console.log('fail', error)
          }
        )
    },

    // 初始化POI 样式
    initStyle() {
      this.styles = {
        Point: new Style({
          image: new CircleStyle({
            radius: 2,
            fill: new Fill({ color: 'grey' }),
          }),
        }),
        // 点集合
        MultiPoint: new Style({
          image: new CircleStyle({
            radius: 2,
            fill: new Fill({ color: 'blue' }),
            stroke: new Stroke({
              color: 'white',
              width: 2,
            }),
          }),
        }),
        // 线集合
        MultiLineString: new Style({
          stroke: new Stroke({
            color: 'rgba(240,248,255, 1)', // 'green'
            width: 3,
          }),
        }),
        // 面集合
        MultiPolygon: new Style({
          stroke: new Stroke({
            color: 'black',
            width: 1.5,
          }),
          fill: new Fill({
            color: 'rgba(240,248,255, 0.7)',
          }),
        }),
        // 定位结果（PDR）
        location: new Style({
          image: new CircleStyle({
            radius: 5,
            fill: new Fill({ color: 'red' }),
            stroke: new Stroke({
              color: 'white',
              width: 2,
            }),
          }),
        }),
        // 路径（PDR）
        path: new Style({
          stroke: new Stroke({
            color: 'green', // 'green'
            width: 2,
          }),
        }),
        // 定位结果（Wifi）
        wifiLocation: new Style({
          image: new CircleStyle({
            radius: 5,
            fill: new Fill({ color: 'blue' }),
            stroke: new Stroke({
              color: 'white',
              width: 2,
            }),
          }),
        }),
        // 路径（wifi）
        wifiPath: new Style({
          stroke: new Stroke({
            color: 'yellow', // 'green'
            width: 2,
          }),
        }),
        // 定位结果（粒子滤波）
        pfLocation:
          // new Style({
          //   image: new CircleStyle({
          //     radius: 5,
          //     fill: new Fill({ color: 'red' }),
          //     stroke: new Stroke({
          //       color: 'white',
          //       width: 2,
          //     }),
          //   }),
          // }),
          new Style({
            image: new Icon({
              anchor: [0.5, 46],
              scale: 0.2,
              //anchorOrigin: 'bottom-left',
              anchorXUnits: 'fraction',
              anchorYUnits: 'pixels',
              crossOrigin: 'anonymous',
              src: './location-fill.png',
            }),
          }),
        // 路径（粒子滤波）
        pfPath: new Style({
          stroke: new Stroke({
            color: 'green', // 'green'
            width: 2,
          }),
        }),
        // 粒子集
        particle: new Style({
          image: new CircleStyle({
            radius: 1,
            fill: new Fill({ color: 'blue' }),
          }),
        }),
        // wifi参考点
        candidate: new Style({
          image: new CircleStyle({
            radius: 4,
            fill: new Fill({ color: 'red' }),
          }),
        }),
      }
    },
    // 地图加载
    initMap() {
      this.map = new olMap({
        target: 'map',
        layers: [],
        view: new olView({
          center: [30000, -70000],
          //projection: 'EPSG:3857',
          // projection: 'EPSG:2406',
          zoom: 10,
          minZoom: 9,
          maxZoom: 14,
          enableRotation: false, // 取消旋转
        }), // 地图图层
      })

      let features = []

      this.baseFeature.forEach((geojson) => {
        features = features.concat(new GeoJSON().readFeatures(geojson))
      })

      let baseLayer = new VectorLayer({
        source: new VectorSource({
          features: features,
        }),
        style: (feature) => {
          return this.styles[feature.getGeometry().getType()]
        },
      })
      this.map.addLayer(baseLayer)
    },
    // 初始化鼠标坐标控制器
    initMousePositionControl() {
      // 鼠标位置
      this.mousePositionControl = new MousePosition({
        // coordinateFormat: createStringXY(4), // 默认格式 **,**
        coordinateFormat: function (e) {
          // 自定义格式
          // 这里格式化成 X: **  Y: **
          let stringifyFunc = createStringXY(2) // 坐标小数点位数
          let str = stringifyFunc(e)
          return (
            'X: ' + str.split(',')[0] + '&nbsp;' + ' Y: ' + str.split(',')[1]
          )
        },
        //projection: 'EPSG:4326', // 和地图坐标系保持一致
        className: 'custom-mouse-position', // css类名
        target: document.getElementById('mousePosition'), // 绑定到DOM
      })
      // 添加控制控件到地图上即可
      this.map.addControl(this.mousePositionControl)
    },
    // 更新全图POI列表
    updatePointFeatures() {
      this.pointFeatures = this.pointSource.getFeatures()
      // this.pointSource.forEachFeature(function (e) {
      //   console.log(e.id_ , toStringXY(e.getGeometry().getCoordinates()))
      // })
    },
    // 清空图层
    clearView() {
      this.scenes.forEach((value, key) => {
        console.log('clearView')
        this.pointSource.removeFeature(this.pointSource.getFeatureById(key))
        this.pathSource.removeFeature(this.pathSource.getFeatureById(key))
      })
    },
    // 以初始坐标 geojson 添加POI
    // 移除某一系列 POI
    removeFeature(name) {
      console.log(' remove Feature', name)
      this.pointSource.removeFeature(this.pointSource.getFeatureById(name))
      this.pathSource.removeFeature(this.pathSource.getFeatureById(name))
      this.updatePointFeatures()
    },

    // 以 url+name 接入webSocket服务器, 设置消息回调为 onmessageFunc
    concat(name, url, onmessageFunc) {
      if (this.webSockets.has(name)) {
        this.webSockets.get(name).close()
      }
      //判断当前浏览器是否支持WebSocket
      if ('WebSocket' in window) {
        let socketUrl = url + name
        this.webSockets.set(name, new WebSocket(socketUrl))
      } else {
        alert('Not support websocket')
      }
      //连接发生错误的回调方法
      this.webSockets.get(name).onerror = () => {
        console.log('socket连接失败')
      }
      //连接成功建立的回调方法
      this.webSockets.get(name).onopen = () => {
        console.log('socket连接已打开')
      }

      //连接关闭的回调方法
      this.webSockets.get(name).onclose = () => {
        console.log('socket连接已关闭')
      }
      //接收到消息的回调方法
      this.webSockets.get(name).onmessage = onmessageFunc
      //听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
      window.onbeforeunload = () => {
        this.websocket.close()
      }
    },
    // 关闭websocket连接
    closeWebSocket() {
      this.webSockets.forEach((websocket) => {
        websocket.close()
      })
    },
    // 定时器方式获取（轮询）
    startLocation(name) {
      console.log('start location')
      this.timer = setInterval(() => {
        axios.get('/api1/point/pointSender').then(
          (response) => {
            // console.log('请求成功', response.data)
            let msg = response.data
            console.log('now location is (', msg.data.x, ',', msg.data.y, ')')
            if (this.pointSource.getFeatureById(name) === null) {
              this.addFeature1(name, msg.data.x, msg.data.y, 'location', 'path')
            } else {
              this.movePointTo1(name, msg.data.x, msg.data.y)
            }
          },
          (error) => {
            console.log('请求失败', error.message)
          }
        )
      }, 100)
    },
    // 停止定位（全部）
    stopLocation() {
      clearInterval(this.timer)
      this.closeWebSocket()
    },
    // 开始wifi定位演示
    startWifiLocation(name) {
      this.concat(
        name,
        'ws://47.101.186.100:9200/websocket/wifilocation/',
        (event) => {
          // console.log(event.data)
          let msg = JSON.parse(event.data)
          // console.log('data from server', msg)
          let user = msg.userName
          if (msg.topic === 'location') {
            // console.log(msg.wifiLocation)
            let wifiGeojson = JSON.parse(msg.data.wifiLocation)
            console.log();
            let candidateReferences = JSON.parse(msg.data.candidateReferences)
            //console.log('wifiGeojson', wifiGeojson, 'candidateReferences', candidateReferences)
            // 初始化该场景
            if (!this.scenes.has(name)) {
              this.scenes.set(name, '')
              this.pointSources[name] = new VectorSource({
                features: [],
              })
              // 添加该场景图层
              this.map.addLayer(
                new VectorLayer({
                  name: name,
                  source: this.pointSources[name],
                  style: (feature) => {
                    if (feature.getProperties().weight) {
                      // 参考点候选
                      let radius = feature.getProperties().weight < 0.5 ? 3 : 5
                      return new Style({
                        image: new CircleStyle({
                          radius: radius,
                          fill: new Fill({ color: 'green' }),
                        }),
                      })
                    } else {
                      // wifi定位点
                      // console.log(
                      //   'location style',
                      //   feature.getGeometry().getFlatCoordinates()
                      // )
                      return new Style({
                        image: new CircleStyle({
                          radius: 4,
                          fill: new Fill({ color: 'red' }),
                        }),
                      })
                    }
                  },
                })
              )
              // 添加线图层
              this.pathSources[name] = new VectorSource({
                features: [],
              })
              this.map.addLayer(
                new VectorLayer({
                  name: name,
                  source: this.pathSources[name],
                  style: (feature) => {
                    return this.styles[feature.get('type')]
                  },
                })
              )
              let path = new olFeature({
                geometry: new LineString([]), // 二维数组
                type: 'wifiPath',
              })
              path
                .getGeometry()
                .appendCoordinate(wifiGeojson.geometry.coordinates)
              path.setId(name)
              this.pathSources[name].addFeature(path)
            }

            this.pointSources[name].clear()
            this.pointSources[name].addFeature(
              new GeoJSON().readFeature(wifiGeojson) // 读取wifi定位信息
            )
            this.pointSources[name].addFeatures(
              new GeoJSON().readFeatures(candidateReferences) // 读取候选参考点信息
            )

            this.pathSources[name]
              .getFeatureById(name)
              .getGeometry()
              .appendCoordinate(wifiGeojson.geometry.coordinates)
            console.log('wifilocation', wifiGeojson.geometry.coordinates, Date.now())
          } else {
            console.log('other msg', msg.message, msg.data)
          }
        }
      )
    },
    // 开始PDR+wifi演示
    startPFPDRLocation(name) {
      this.concat(
        name,
        'ws://47.101.186.100:9103/websocket/location/',
        (event) => {
          let msg = JSON.parse(event.data)
          console.log('data from server', msg)
          let user = msg.userName
          if (msg.topic === 'location') {
            let geojson = JSON.parse(msg.data.location)
            let particlesJson = JSON.parse(msg.data.particles)
            let location = new GeoJSON().readFeature(geojson)
            location.setProperties({ type: 'pfLocation' })
            location.setId('location')
            let particles = new GeoJSON().readFeature(particlesJson)
            particles.setProperties({ type: 'particle' })
            particles.setId('particles')
            // console.log('location',location)
            // console.log('particles',particles)
            if (!this.scenes.has(name)) {
              this.scenes.set(name, '')
              this.pointSources[name] = new VectorSource({
                features: [],
              })
              // 添加该场景图层
              this.map.addLayer(
                new VectorLayer({
                  name: name,
                  source: this.pointSources[name],
                  style: (feature) => {
                    return this.styles[feature.get('type')]
                  },
                })
              )
              // 添加线图层
              this.pathSources[name] = new VectorSource({
                features: [],
              })
              this.map.addLayer(
                new VectorLayer({
                  name: name,
                  source: this.pathSources[name],
                  style: (feature) => {
                    return this.styles[feature.get('type')]
                  },
                })
              )
              this.pointSources[name].addFeature(location)
              this.pointSources[name].addFeature(particles)

              let path = new olFeature({
                geometry: new LineString([]), // 二维数组
                type: 'pfPath',
              })
              path.getGeometry().appendCoordinate(geojson.geometry.coordinates)
              path.setId('pfPath')
              this.pathSources[name].addFeature(path)
            } else {
              this.pointSources[name]
                .getFeatureById('location')
                .getGeometry()
                .setCoordinates(geojson.geometry.coordinates)
              this.pointSources[name].removeFeature(
                this.pointSources[name].getFeatureById('particles')
              )
              this.pointSources[name].addFeature(particles)
              this.pathSources[name]
                .getFeatureById('pfPath')
                .getGeometry()
                .appendCoordinate(geojson.geometry.coordinates)
            }
            // if (this.pointSource.getFeatureById(user) === null) {
            //   this.addFeature(user, geojson, 'pfLocation', 'pfPath')
            // } else {
            //   // 只显示wifi定位结果，不显示路径
            //   this.movePointTo(user, geojson)
            // }
            // this.updateParticles('particle', particlesJson, 'particle')
          } else if (msg.topic === 'orientation') {
            // 当前还没有定位点
            if (!this.scenes.has(name)) return
            this.pointSource[name].getFeatureById('location')
          } else {
            console.log('other msg', msg.message, msg.data)
          }
        }
      )
    },
    // 更新粒子集
    updateParticles(name, geojson, featureType) {
      let particles = new GeoJSON().readFeature(geojson)
      particles.setProperties({ type: featureType })
      particles.setId(name)
      this.pointSource.removeFeature(this.pointSource.getFeatureById(name))
      this.pointSource.addFeature(particles)
    },

    // 更新粒子集
    updateCandidates(name, geojson, featureType) {
      let particles = new GeoJSON().readFeatures(geojson)
      this.pointSource.removeFeature(this.pointSource.getFeatureById(name))
      particles.forEach((particle) => {
        console.log()
        particle.setProperties({ type: featureType })
        particle.setId(name)
        console.log('candidate', particle.getGeometry().flatCoordinates)
        this.pointSource.addFeature(particle)
      })
    },

    moveDemo() {
      let demoName = 'demo'
      this.scenes.set(demoName, '')
      this.pointSources[demoName] = new VectorSource({
        features: [],
      })
      // 添加点图层
      this.map.addLayer(
        new VectorLayer({
          name: demoName,
          source: this.pointSources[demoName],
          style: (feature) => {
            return this.styles[feature.get('type')]
          },
        })
      )
      // 添加线图层
      this.pathSources[demoName] = new VectorSource({
        features: [],
      })
      this.map.addLayer(
        new VectorLayer({
          name: demoName,
          source: this.pathSources[demoName],
          style: (feature) => {
            return this.styles[feature.get('type')]
          },
        })
      )
      var demoCoordinates = [
        [47694.444, -103222.222],
        [47000.0, -103083.333],
        [46305.556, -102944.444],
        [45611.111, -102916.667],
        [44972.222, -102916.667],
        [44277.778, -102972.222],
        [43638.889, -102944.444],
        [42972.222, -102916.667],
        [42305.556, -102888.889],
        [41666.667, -102833.333],
        [40972.222, -102805.556],
        [40333.333, -102750.0],
        [39638.889, -102722.222],
        [38916.667, -102750.0],
        [38222.222, -102805.556],
        [37555.556, -102833.333],
        [36888.889, -102888.889],
        [36166.667, -103027.778],
        [35472.222, -103111.111],
        [34777.778, -103138.889],
        [34083.333, -103166.667],
        [33416.667, -103194.444],
        [32694.444, -103194.444],
        [32000.0, -103138.889],
        [31333.333, -103000.0],
        [30666.667, -102944.444],
        [29944.444, -102861.111],
        [29277.778, -102805.556],
        [28583.333, -102666.667],
        [27944.444, -102583.333],
        [27277.778, -102388.889],
        [26611.111, -102333.333],
        [25916.667, -102250.0],
        [25250.0, -102305.556],
        [24583.333, -102277.778],
        [23944.444, -102277.778],
        [23250.0, -102305.556],
        [22611.111, -102277.778],
        [21916.667, -102222.222],
        [21277.778, -102250.0],
        [20583.333, -102305.556],
        [19916.667, -102361.111],
        [19222.222, -102333.333],
        [18555.556, -102333.333],
        [17888.889, -102361.111],
        [17222.222, -102416.667],
        [14666.667, -102472.222],
        [13972.222, -102500.0],
        [13305.556, -102472.222],
        [12666.667, -102444.444],
        [12027.778, -102388.889],
        [11388.889, -102361.111],
        [11388.889, -101666.667],
        [11333.333, -100944.444],
        [11333.333, -100250.0],
        [11527.778, -99555.556],
        [11666.667, -98805.556],
        [11722.222, -98166.667],
        [11805.556, -97472.222],
        [11805.556, -96777.778],
        [11888.889, -96083.333],
        [11916.667, -95388.889],
        [12083.333, -94694.444],
        [12083.333, -94027.778],
        [12166.667, -93333.333],
        [12222.222, -92666.667],
        [12361.111, -92000.0],
        [12472.222, -91333.333],
        [12527.778, -90638.889],
        [12527.778, -90000.0],
        [12472.222, -89305.556],
        [12444.444, -88638.889],
        [12388.889, -87944.444],
        [12361.111, -87277.778],
        [12361.111, -86611.111],
        [12361.111, -85944.444],
        [12361.111, -85250.0],
        [12333.333, -84555.556],
        [12444.444, -83861.111],
        [12444.444, -83194.444],
        [12472.222, -82500.0],
        [12416.667, -81805.556],
        [12416.667, -81111.111],
        [12361.111, -80444.444],
        [12388.889, -79777.778],
        [12416.667, -79083.333],
        [12361.111, -78388.889],
        [12361.111, -77722.222],
      ]
      console.log(demoCoordinates[0])
      let location = new olFeature({
        geometry: new Point(demoCoordinates[0]),
        type: 'pfLocation',
      })
      location.setId('location')
      this.pointSources[demoName].addFeature(location)
      let path = new olFeature({
        geometry: new LineString([demoCoordinates[0]]), // 二维数组
        type: 'pfPath',
      })
      path.setId('pfPath')
      this.pathSources[demoName].addFeature(path)

      for (let i = 1; i < demoCoordinates.length; i++) {
        let current = this.pointSources[demoName]
          .getFeatureById('location')
          .getGeometry()
          .getCoordinates()
        let next = demoCoordinates[i]
        this.pointSources[demoName]
          .getFeatureById('location')
          .getGeometry()
          .setCoordinates(next)
        this.pathSources[demoName]
          .getFeatureById('pfPath')
          .getGeometry()
          .appendCoordinate(next)
      }
    },
  },
  computed: {
    ...mapState(['devices']),
  },
  watch: {
    baseFeature(newValue) {
      if (newValue.length > 2) {
        // WMS地图数据读取完了再渲染
        this.initMap()
        this.initMousePositionControl()
      }
    },
  },
  mounted() {
    this.initStyle()
    this.initWebSource()
    // this.initMap()
    // this.initMousePositionControl()
  },
}
</script>

<style scoped>
.map {
  width: 90%;
  height: 800px;
  /* width: 600px;
  height: 600px;
  margin: 0 auto; */
  border: 2px solid #000;
}

.anchor {
  display: inline-block;
  height: 15px;
  width: 15px;
  background-color: red;
  border-radius: 50%;
}
</style>
